const Promise = function (executer) {
    if (this === window) {
        return new arguments.callee(executer)
    } else {
        this.promiseState = "pending";
        this.promiseResult = undefined;
    }
    const pack_Resolve_Reject = (state, val, flag) => { //封装简化代码
        if (this.promiseState !== "pending") return;
        this.promiseState = state;
        this.promiseResult = val;
        if (Promise.arr.length && flag) Promise.arr.forEach( x => x.succ())
        if (Promise.arr.length && !flag) Promise.arr.forEach( x => x.err())
        Promise.arr.splice(0)
    }
    const resolve = value => pack_Resolve_Reject("fulfilled", value, true)
    const reject = reason => pack_Resolve_Reject("rejected", reason, false)
    try {
        executer(resolve, reject)
    } catch (error) {
        reject(error)
        console.error("错误是:", error);
    }
}

const init = new Promise(() => { })
delete init.promiseState
delete init.promiseResult
Promise.prototype = Object.create(init)

Object.defineProperties(Promise.prototype, {
    then: {
        value: function (onSuccess, onReject) {
            onSuccess = typeof onSuccess !== "function" ? value => value : onSuccess
            onReject = typeof onReject !== "function" ? reason => new Promise((resolve, reject) => reject(reason)) : onReject
            return new Promise(
                (resolve, reject) => {
                    const stateChange = fn => {
                        try {
                            setTimeout(() => {
                                let result = fn(this.promiseResult);
                                result instanceof Promise ? result.then(resolve, reject) : resolve(result)
                            });
                        } catch (error) {
                            reject(error)
                            console.error("错误是:", error);
                        }
                    }
                    if (this.promiseState === "fulfilled") stateChange(onSuccess)

                    if (this.promiseState === "rejected") stateChange(onReject)

                    if (this.promiseState === "pending") {
                        Promise.arr.push(
                            {
                                succ: () => {
                                    stateChange(onSuccess)
                                },
                                err: () => {
                                    stateChange(onReject)
                                }
                            }
                        )
                    }
                }
            )
        }
    },
    catch: {
        value: function (onReject) {
            return this.then(null, onReject)
        }
    }
});

Object.defineProperties(Promise, {
    arr: { //给构造函数身上绑定一个属性，为了使同一个promsie对象可以多次调用then方法
        value: new Array()
    },
    resolve: {
        value: function (value) {
            return new Promise(
                (resolve, reject) => {
                    value instanceof Promise ? value.then(resolve, reject) : resolve(value)
                }
            )
        }
    },
    reject: {
        value: function (value) {
            return new Promise(
                (resolve, reject) => {
                    reject(value)
                }
            )
        }
    },
    all: {
        value: function (promiseArr) {
            let newArr = [];
            return new Promise(
                (resolve, reject) => {
                    promiseArr.forEach(
                        (item, index) => {
                            item.then(
                                success => {
                                    newArr[index] = success
                                    if (newArr.length === promiseArr.length) resolve(newArr)
                                },
                                reason => reject(reason)
                            )
                        }
                    )
                }
            )
        }
    },
    race: {
        value: function (promiseArr) {
            return new Promise(
                (resolve, reject) => {
                    promiseArr.forEach(
                        (item) => {
                            item.then(
                                success => {
                                    resolve(success)
                                },
                                reason => {
                                    reject(reason)
                                }
                            )
                        }
                    )
                }
            )
        }
    }
})
